package net.amsoft.iservice.ilink.util;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import net.amsoft.iservice.ilink.hibernate.IBroker;
import net.amsoft.iservice.ilink.hibernate.ILinkBaseClass;
import net.amsoft.iservice.ilink.hibernate.Redirect;
import net.amsoft.iservice.ilink.hibernate.Synonym;
import net.amsoft.iservice.util.exception.IServiceException;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.apache.log4j.Logger;

/**
 * public class ILinkHelpers This class provides the main interface between the
 * service layer and the database. Different APIs provided in this class can be
 * used to fetch data objects of hibernate entities which can be used to
 * communicate with database tables. The class ILinkHelpers includes methods for
 * fetching data objects of IBroker, Synonym etc. Apart from this some APIs are
 * also provided to save nad remove redirects form the database. No constructor
 * is provided for this class, all the public static APIs provided in this class
 * can be used without any object to class ILinkHelpers.
 * 
 */
public class ILinkHelpers {
	public static final Logger oLogger = Logger.getLogger(ILinkHelpers.class);

	/**
	 * API returns object of class cClass, fetch() uses id and returns a general
	 * object to cClass.
	 * 
	 * @param Class
	 *            fetch object of this class
	 * @param id
	 *            use this id to fetch object
	 * @param oTransaction
	 *            hibernate transaction for current session
	 * @param oSession
	 *            hibernate session for user's current requests
	 * @return Object
	 * 
	 * returns the object with the supplied id from the specified class.
	 * @throws IServiceException
	 */
	public static Object fetch(Class cClass, Long id, Session oSession,
			Transaction oTransaction) throws IServiceException {
		oLogger.info("fetch() : entry with data : Id: " + id);
		ILinkBaseClass oILinkObject = (ILinkBaseClass) oSession
				.load(cClass, id);
		if (oILinkObject == null) {
			oLogger.warn("fetch() : throw exception : ILinkObject is: "
					+ oILinkObject);
			throw new IServiceException(oLogger, 2030);
		} else
			oILinkObject.update();
		oLogger.info("fetch() : exit, return ILinkObject: " + oILinkObject);
		return (oILinkObject);
	}

	/**
	 * This method fetches data object of Synonym class using its name
	 * 
	 * @param sName
	 *            name of the synonym
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @return Synonnym Returns the Synonym object for the synonym passed
	 * @throws IServiceException
	 */
	public static Synonym fetchSynonym(String sName, Session oSession,
			Transaction oTransaction) throws IServiceException {
		oLogger.info("fetchSynonym() : entry with data : Name:" + sName);
		Synonym oSynonym = new Synonym();
		Criteria oCriteria = oSession.createCriteria(Synonym.class);
		oCriteria.add(Expression.eq("synonym", sName));
		oCriteria.add(Expression.eq("state", Short
				.valueOf((short) ILinkConstants.STATE_ACTIVE)));
		oSynonym = (Synonym) oCriteria.uniqueResult();
		if (oSynonym == null) {
			oLogger.warn("fetch() : throw exception : Synonym is: " + oSynonym);
			throw new IServiceException(2020, false);
		}
		oLogger.info("fetchSynonym() : return Synonym: " + oSynonym);
		return (oSynonym);
	}

	/**
	 * Gets all the synonyms subscribed for the Principal which belongs to the
	 * given synonym
	 * 
	 * @param oSynonym
	 *            object of the Synonym class
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @return list of Synonyms
	 * 
	 */
	public static List fetchAllSynonyms(Synonym oSynonym, Session oSession,
			Transaction oTransaction) {
		oLogger.info("fetchAllSynonyms() : entry with data : Synonym: "
				+ oSynonym.getSynonym());
		Criteria oCriteria = oSession.createCriteria(Synonym.class);
		oCriteria.add(Expression.eq("subscriber", oSynonym.getSubscriber()));
		oCriteria.add(Expression.eq("state", Short
				.valueOf((short) ILinkConstants.STATE_ACTIVE)));
		oCriteria.addOrder(Order.asc("id"));
		List oSynonymList = oCriteria.list();
		oLogger.info("fetchAllSynonyms() : exit, return Synonym List: "
				+ oSynonymList);
		return oSynonymList;
	}

	/**
	 * This API is used to fetch the data object of IBroker class using its
	 * server name
	 * 
	 * @param sServerName
	 *            server name of the required IBroker
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @return IBroker object
	 * @throws IServiceException
	 */
	public static IBroker fetchIBroker(String sServerName, Session oSession,
			Transaction oTransaction) throws IServiceException {
		oLogger.info("fetchIBroker() : entry with data : ServerName: "
				+ sServerName);
		IBroker oIBroker = new IBroker();
		Criteria oCriteria = oSession.createCriteria(IBroker.class);
		oCriteria.add(Expression.eq("serverName", sServerName));
		oCriteria.add(Expression.eq("state", Short
				.valueOf(ILinkConstants.STATE_ACTIVE)));
		oIBroker = (IBroker) oCriteria.uniqueResult();
		if (oIBroker == null) {
			oLogger.warn("fetchIBroker() : throw exception : IBroker is: "
					+ oIBroker);
			throw new IServiceException(2004, false);
		}
		oLogger.info("fetchIBroker() : exit, return IBroker: " + oIBroker);
		return (oIBroker);
	}

	/**
	 * Gets the all the redirects which belong to the given synonym
	 * 
	 * @param sSynonym
	 *            name of the synonym
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @return Map of all redirects the synonym passed
	 */
	public static Set fetchRedirects(String sSynonym, Session oSession,
			Transaction oTransaction) {
		oLogger.info("fetchRedirects() : entry with data : Synonym: "
				+ sSynonym);
		try {
			Synonym oSynonym = ILinkHelpers.fetchSynonym(sSynonym, oSession,
					oTransaction);
			oSynonym.update();
			Set oRedirectSet = oSynonym.getRedirectSet();
			oLogger.info("fetchRedirects() : exit, return RedirectMap: "
					+ oRedirectSet);
			return oRedirectSet;
		} catch (Exception e) {
			oLogger.warn("fetchRedirects() : Exception : " + e.getMessage());
		}
		oLogger.info("fetchRedirects() : exit, return RedirectMap: " + null);
		return null;
	}

	/**
	 * This API is used to get the Redirect related to given synonym using its
	 * tag name
	 * 
	 * @param sSynonym
	 *            name of the synonym
	 * @param sTagName
	 *            name of the tag for redirect
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @return Redirect of given tag name
	 * @throws IServiceException
	 */
	public static Redirect fetchRedirectByTag(String sSynonym, String sTagName,
			Session oSession, Transaction oTransaction)
			throws IServiceException {
		oLogger.info("fetchRedirectByTag() : entry with data : Synonym: "
				+ sSynonym + ", TagName: " + sTagName);
		Synonym oSynonym = ILinkHelpers.fetchSynonym(sSynonym, oSession,
				oTransaction);
		oSynonym.update();
		Set oRedirectSet = (Set) oSynonym.getRedirectSet();
		for (Iterator iterator = oRedirectSet.iterator(); iterator.hasNext();) {
			Redirect oRedirect = new Redirect();
			oRedirect = (Redirect) iterator.next();
			if (oRedirect.getTag().equals(sTagName)) {
				return oRedirect;
			}
		}
		oLogger.info("fetchRedirectByTag() : exit, return Redirect: null");
		return null;
	}

	/**
	 * Saves the redirect object for the given synonym
	 * 
	 * @param sSynonym
	 *            name of the synonym
	 * @param oRedirectMap
	 *            RedirectMap object
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @throws IServiceException
	 */
	public static void saveRedirect(String sSynonym, Set oRedirectSet,
			Session oSession, Transaction oTransaction)
			throws IServiceException {
		oLogger.info("saveRedirect() : entry with data : Synonym: " + sSynonym);
		Synonym oSynonym = ILinkHelpers.fetchSynonym(sSynonym, oSession,
				oTransaction);
		oSynonym.setRedirectSet(oRedirectSet);

		oSynonym.update();
		oLogger.info("saveRedirect() : exit after update");
	}

	/**
	 * Removes the Redirect of a synonym using the tag name of the redirect
	 * 
	 * @param sSynonym
	 *            name of the snonym
	 * @param sTagName
	 *            name of the tag for redirect
	 * @param oSession
	 *            hibernate session
	 * @param oTransaction
	 *            hibernate transaction
	 * @throws IServiceException
	 */
	public static void removeRedirect(String sSynonym, String sTagName,
			Session oSession, Transaction oTransaction)
			throws IServiceException {
		oLogger.info("removeRedirect() : entry with data : Synonym: "
				+ sSynonym + ", Tagname: " + sTagName);
		Synonym oSynonym = ILinkHelpers.fetchSynonym(sSynonym, oSession,
				oTransaction);

		Set oRedirectSet = oSynonym.getRedirectSet();
		oRedirectSet.remove(fetchRedirectByTag(sSynonym, sTagName, oSession,
				oTransaction));
		oSynonym.setRedirectSet(oRedirectSet);
		oSynonym.update();
		oLogger.info("removeRedirect() : exit after update");
	}
}